﻿/**
 * Fast loader/parser XML nodes
 * 
 * Recursively pars XMLNode and create an similar object to the structure of XMLNode
 * 
 * @author	Kliment
 * @version	3.5.10
*/
dynamic class kliment.data.XMLObject {
	private static var _ignorKeys:Array = [0];
	private var _xmlNode:XMLNode;
	private var _parent:XMLObject;
	
	public var attributes:Object = null;
	
	public function get length():Number { return 1 }
	public function get parent():XMLObject { return _parent }
	
	public function XMLObject(xmlNode:XMLNode, parent:XMLObject) {
		if (parent != null) _parent = parent;
		if (xmlNode instanceof XMLNode){
			_xmlNode = xmlNode;
			_parsNode(_xmlNode);
		}
		this[0] = this;
	}
	
	public function value():String {
		return toString();
	}
	
	public function toString():String {
		var temp = _xmlNode.firstChild.nodeValue;
		return temp || null;
	}
	
	public function toXML(mainNodeName:String):XML {
		return new XML(toXMLString(mainNodeName));
	}
	
	public function toXMLString(mainNodeName:String):String {
		if (mainNodeName && mainNodeName.length > 0)
			return _toStringNode(mainNodeName, this);
		else 
			return _assembleNode(this);
	}
	
	private function _parsNode(xmlNode:XMLNode):Void {
		if (xmlNode.attributes){
			attributes = new Object();
			for (var i in _xmlNode.attributes)
				attributes[i] = xmlNode.attributes[i];
		}
		
		var count:Number = xmlNode.childNodes.length;
		for (var i:Number = 0; i < count; ++i) {
			var node:XML = xmlNode.childNodes[i];
			var nodeName:String = node.nodeName;
			if (node.nodeName) 
				_addValue(nodeName, new XMLObject(node, this));
		}
	}
	
	private function _addValue(name:String, value):Void {
		if (this[name]) {
			if (!(this[name] instanceof Array))
				this[name] = new Array(this[name]);
			this[name].push(value);
		} else 
			this[name] = value;
	}
	
	private function _assembleNode(value:XMLObject):String {
		var forReturn:String = '';
		for (var i in value)
			if (value[i] instanceof XMLObject) {
				if (value[i].value() != null){
					forReturn += _toStringNodeValue(i, value[i]);
				} else if (!_ignoredKey(i)){
					forReturn += _toStringNode(i, value[i]);
				}
			} else if (value[i] instanceof Array) {
				forReturn += _arrayToXMLString(value[i], i);
			}
		return forReturn;
	}
	
	private function _toStringNodeValue(mame:String, value:XMLObject):String {
		return "\n<" + mame + _attributes(value) + ">" + value.value() + "</" + mame + ">";
	}
	
	private function _toStringNode(mame:String, value:XMLObject):String {
		return "\n<" + mame + _attributes(value) + ">" + _assembleNode(value) + "\n</" + mame + ">";
	}
	
	private function _arrayToXMLString(src:Array, tagName:String):String {
		var forReturn:String = '';
		var len:Number = src.length;
		for (var i:Number = 0; i < len; i++)
			if (src[i].value())
				forReturn += _toStringNodeValue(tagName, src[i]);
			else 
				forReturn += _toStringNode(tagName, src[i]);
		return forReturn;
	}
	
	private function _attributes(src:XMLObject):String {
		var forReturn:String = '';
		for (var i in src.attributes)
			forReturn += ' ' + i + '="' + src.attributes[i] + '"';
		return forReturn;
	}
	
	private function _ignoredKey(key):Boolean {
		for (var i in _ignorKeys)
			if (_ignorKeys[i] == key)
				return true;
		return false;
	}
}